﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Windows.Forms;
using TomanuExtensions;
using RaytracerLib.Script;
using RaytracerLib.MathLib;
using Raytracer.PropertyGridDecorators;

namespace Raytracer
{
    public static class PropertiesManager
    {
        public static PropertyGrid PropertyGrid;
        private static Dictionary<Type, ConstructorInfo> m_map =
            new Dictionary<Type, ConstructorInfo>();

        static PropertiesManager()
        {
            var asm = System.Reflection.Assembly.GetAssembly(typeof(PropertiesManager));

            foreach (var type in asm.GetTypes())
            {
                if (type.IsAbstract)
                    continue;
                if (type.IsInterface)
                    continue;
                if (type.IsNested)
                    continue;
                if (!type.Name.EndsWith("Properties"))
                    continue;
                if (!type.FullName.StartsWith("Raytracer.PropertyGridDecorators"))
                    continue;
                if (type.Name.StartsWith("ScriptParam"))
                    continue;

                if (type.GetConstructors().Count() != 1)
                    continue;

                var ci = type.GetConstructors().First();

                if (ci.GetParameters().Count() != 1)
                    continue;

                m_map.Add(ci.GetParameters().First().ParameterType, ci);
            }
        }

        public static void Update(Object a_obj)
        {
            if (a_obj != null)
            {
                var temp = a_obj.GetType().GetInterfaces().Concat(
                    new[] { a_obj.GetType() }).Concat(a_obj.GetType().GetBaseTypes());

                // In example IFileArrayBase is derived from IArrayBase,
                // Place IFileArrayBase before IArrayBase in types.
                var types = from t in temp
                            orderby temp.Intersect(t.GetInterfaces().Concat(
                                t.GetBaseTypes())).Count() descending
                            select t;

                foreach (var type in types)
                {
                    ConstructorInfo ci;
                    if (m_map.TryGetValue(type, out ci))
                    {
                        PropertyGrid.SelectedObject = ci.Invoke(a_obj);
                        return;
                    }
                }
            }

            if (a_obj is ScriptParam)
            {
                ScriptParam param = a_obj as ScriptParam;

                if (param.Value is ColorFloat)
                {
                    PropertyGrid.SelectedObject = new ScriptParamColorFloatProperties(param);
                    return;
                }
                else if (param.Value is Double)
                {
                    PropertyGrid.SelectedObject = new ScriptParamDoubleProperties(param);
                    return;
                }
            }

            PropertyGrid.SelectedObject = null;
        }
    }
}